﻿using System;
using System.Collections.Generic;
using FortuneUniverse.Fortune.Algorithms;

namespace FortuneUniverse.Fortune.Dyson
{
  public abstract class PlanetAlgorithm
  {
    protected int seed;
    protected PlanetData planet;

    public void Reset(int _seed, PlanetData _planet)
    {
      this.seed = _seed;
      this.planet = _planet;
    }

    public abstract void GenerateTerrain(double modX, double modY);

    public virtual void GenerateVeins(StarData star, GalaxyData galaxy, bool sketchOnly)
    {
      ThemeProto themeProto = LDB.themes.Select(this.planet.theme);
      if (themeProto == null)
        return;
      URandom1 urandom1_1 = new URandom1(this.planet.seed);
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      int _birthSeed = urandom1_1.Next();
      URandom1 urandom1_2 = new URandom1(urandom1_1.Next());
      PlanetRawData data = this.planet.data;
      float num1 = 2.1f / this.planet.radius;
      VeinProto[] veinProtos = PlanetModelingManager.veinProtos;
      int[] veinModelIndexs = PlanetModelingManager.veinModelIndexs;
      int[] veinModelCounts = PlanetModelingManager.veinModelCounts;
      int[] veinProducts = PlanetModelingManager.veinProducts;
      int[] numArray1 = new int[veinProtos.Length];
      float[] numArray2 = new float[veinProtos.Length];
      float[] numArray3 = new float[veinProtos.Length];
      if (themeProto.VeinSpot != null)
        Array.Copy((Array) themeProto.VeinSpot, 0, (Array) numArray1, 1, Math.Min(themeProto.VeinSpot.Length, numArray1.Length - 1));
      if (themeProto.VeinCount != null)
        Array.Copy((Array) themeProto.VeinCount, 0, (Array) numArray2, 1, Math.Min(themeProto.VeinCount.Length, numArray2.Length - 1));
      if (themeProto.VeinOpacity != null)
        Array.Copy((Array) themeProto.VeinOpacity, 0, (Array) numArray3, 1, Math.Min(themeProto.VeinOpacity.Length, numArray3.Length - 1));
      float p = 1f;
      ESpectrType spectr = star.spectr;
      switch (star.type)
      {
        case EStarType.MainSeqStar:
          switch (spectr)
          {
            case ESpectrType.M:
              p = 2.5f;
              break;
            case ESpectrType.K:
              p = 1f;
              break;
            case ESpectrType.G:
              p = 0.7f;
              break;
            case ESpectrType.F:
              p = 0.6f;
              break;
            case ESpectrType.A:
              p = 1f;
              break;
            case ESpectrType.B:
              p = 0.4f;
              break;
            case ESpectrType.O:
              p = 1.6f;
              break;
          }
          break;
        case EStarType.GiantStar:
          p = 2.5f;
          break;
        case EStarType.WhiteDwarf:
          p = 3.5f;
          ++numArray1[9];
          ++numArray1[9];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.449999988079071; ++index)
            ++numArray1[9];
          numArray2[9] = 0.7f;
          numArray3[9] = 1f;
          ++numArray1[10];
          ++numArray1[10];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.449999988079071; ++index)
            ++numArray1[10];
          numArray2[10] = 0.7f;
          numArray3[10] = 1f;
          ++numArray1[12];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.5; ++index)
            ++numArray1[12];
          numArray2[12] = 0.7f;
          numArray3[12] = 0.3f;
          break;
        case EStarType.NeutronStar:
          p = 4.5f;
          ++numArray1[14];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.649999976158142; ++index)
            ++numArray1[14];
          numArray2[14] = 0.7f;
          numArray3[14] = 0.3f;
          break;
        case EStarType.BlackHole:
          p = 5f;
          ++numArray1[14];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.649999976158142; ++index)
            ++numArray1[14];
          numArray2[14] = 0.7f;
          numArray3[14] = 0.3f;
          break;
      }
      for (int index1 = 0; index1 < themeProto.RareVeins.Length; ++index1)
      {
        int rareVein = themeProto.RareVeins[index1];
        float num2 = star.index != 0 ? themeProto.RareSettings[index1 * 4 + 1] : themeProto.RareSettings[index1 * 4];
        float rareSetting1 = themeProto.RareSettings[index1 * 4 + 2];
        float rareSetting2 = themeProto.RareSettings[index1 * 4 + 3];
        float num3 = rareSetting2;
        float num4 = 1f - Mathf.Pow(1f - num2, p);
        float num5 = 1f - Mathf.Pow(1f - rareSetting2, p);
        float num6 = 1f - Mathf.Pow(1f - num3, p);
        if (urandom1_1.NextDouble() < (double) num4)
        {
          ++numArray1[rareVein];
          numArray2[rareVein] = num5;
          numArray3[rareVein] = num5;
          for (int index2 = 1; index2 < 12 && urandom1_1.NextDouble() < (double) rareSetting1; ++index2)
            ++numArray1[rareVein];
        }
      }
      bool flag1 = galaxy.birthPlanetId == this.planet.id;
      if (flag1 && !sketchOnly)
        this.planet.GenBirthPoints(data, star, _birthSeed);
      Vector3[] vector3Array = new Vector3[512];
      EVeinType[] eveinTypeArray = new EVeinType[512];
      int length = 0;
      Vector3 vector3_1;
      if (flag1)
      {
        Vector3 birthPoint = this.planet.birthPoint;
        birthPoint.Normalize();
        vector3_1 = birthPoint * 0.75f;
      }
      else
      {
        Vector3 vector3_2;
        vector3_2.x = (float) (urandom1_2.NextDouble() * 2.0 - 1.0);
        vector3_2.y = (float) urandom1_2.NextDouble() - 0.5f;
        vector3_2.z = (float) (urandom1_2.NextDouble() * 2.0 - 1.0);
        vector3_2.Normalize();
        vector3_1 = vector3_2 * (float) (urandom1_2.NextDouble() * 0.4 + 0.2);
      }
      this.planet.veinSpotsSketch = numArray1;
      if (sketchOnly)
        return;
      if (flag1)
      {
        eveinTypeArray[0] = EVeinType.Iron;
        vector3Array[0] = this.planet.birthResourcePoint0;
        eveinTypeArray[1] = EVeinType.Copper;
        vector3Array[1] = this.planet.birthResourcePoint1;
        length = 2;
      }
      for (int index3 = 1; index3 < 15 && length < vector3Array.Length; ++index3)
      {
        EVeinType eveinType = (EVeinType) index3;
        int num7 = numArray1[index3];
        if (num7 > 1)
          num7 += urandom1_2.Next(-1, 2);
        for (int index4 = 0; index4 < num7; ++index4)
        {
          int num8 = 0;
          Vector3 zero = Vector3.zero;
          bool flag2 = false;
          while (num8++ < 200)
          {
            zero.x = (float) (urandom1_2.NextDouble() * 2.0 - 1.0);
            zero.y = (float) (urandom1_2.NextDouble() * 2.0 - 1.0);
            zero.z = (float) (urandom1_2.NextDouble() * 2.0 - 1.0);
            if (eveinType != EVeinType.Oil)
              zero += vector3_1;
            zero.Normalize();
            float num9 = data.QueryHeight(zero);
            if ((double) num9 >= (double) this.planet.radius && (eveinType != EVeinType.Oil || (double) num9 >= (double) this.planet.radius + 0.5))
            {
              bool flag3 = false;
              float num10 = eveinType != EVeinType.Oil ? 196f : 100f;
              for (int index5 = 0; index5 < length; ++index5)
              {
                if ((double) (vector3Array[index5] - zero).sqrMagnitude < (double) num1 * (double) num1 * (double) num10)
                {
                  flag3 = true;
                  break;
                }
              }
              if (!flag3)
              {
                flag2 = true;
                break;
              }
            }
          }
          if (flag2)
          {
            vector3Array[length] = zero;
            eveinTypeArray[length] = eveinType;
            ++length;
            if (length == vector3Array.Length)
              break;
          }
        }
      }
      Array.Clear((Array) this.planet.veinAmounts, 0, this.planet.veinAmounts.Length);
      data.veinCursor = 1;
      this.planet.veinGroups = new PlanetData.VeinGroup[length];
      List<Vector2> vector2List = new List<Vector2>(100);
      VeinData vein = new VeinData();
      for (int index6 = 0; index6 < length; ++index6)
      {
        vector2List.Clear();
        Vector3 normalized = vector3Array[index6].normalized;
        EVeinType eveinType = eveinTypeArray[index6];
        int index7 = (int) eveinType;
        Quaternion rotation = Quaternion.FromToRotation(Vector3.up, normalized);
        Vector3 vector3_3 = rotation * Vector3.right;
        Vector3 vector3_4 = rotation * Vector3.forward;
        this.planet.veinGroups[index6].type = eveinType;
        this.planet.veinGroups[index6].pos = normalized;
        this.planet.veinGroups[index6].count = 0;
        this.planet.veinGroups[index6].amount = 0L;
        vector2List.Add(Vector2.zero);
        int num11 = Mathf.RoundToInt(numArray2[index7] * (float) urandom1_2.Next(20, 25));
        if (eveinType == EVeinType.Oil)
          num11 = 1;
        float num12 = numArray3[index7];
        if (flag1 && index6 < 2)
        {
          num11 = 6;
          num12 = 0.2f;
        }
        int num13 = 0;
        while (num13++ < 20)
        {
          int count = vector2List.Count;
          for (int index8 = 0; index8 < count && vector2List.Count < num11; ++index8)
          {
            if ((double) vector2List[index8].sqrMagnitude <= 36.0)
            {
              double num14 = urandom1_2.NextDouble() * Math.PI * 2.0;
              Vector2 vector2_1 = new Vector2((float) Math.Cos(num14), (float) Math.Sin(num14));
              vector2_1 += vector2List[index8] * 0.2f;
              vector2_1.Normalize();
              Vector2 vector2_2 = vector2List[index8] + vector2_1;
              bool flag4 = false;
              for (int index9 = 0; index9 < vector2List.Count; ++index9)
              {
                if ((double) (vector2List[index9] - vector2_2).sqrMagnitude < 0.850000023841858)
                {
                  flag4 = true;
                  break;
                }
              }
              if (!flag4)
                vector2List.Add(vector2_2);
            }
          }
          if (vector2List.Count >= num11)
            break;
        }
        float resourceCoef = star.resourceCoef;
        if (flag1)
          resourceCoef *= 0.6666667f;
        int num15 = Mathf.RoundToInt(num12 * 100000f * resourceCoef);
        if (num15 < 20)
          num15 = 20;
        int num16 = num15 >= 16000 ? 15000 : Mathf.FloorToInt((float) num15 * (15f / 16f));
        int minValue = num15 - num16;
        int maxValue = num15 + num16 + 1;
        for (int index10 = 0; index10 < vector2List.Count; ++index10)
        {
          Vector3 vector3_5 = (vector2List[index10].x * vector3_3 + vector2List[index10].y * vector3_4) * num1;
          vein.type = eveinType;
          vein.groupIndex = (short) index6;
          vein.modelIndex = (short) urandom1_2.Next(veinModelIndexs[index7], veinModelIndexs[index7] + veinModelCounts[index7]);
          float num17 = 1.1f;
          vein.amount = Mathf.RoundToInt((float) urandom1_2.Next(minValue, maxValue) * num17);
          if (this.planet.veinGroups[index6].type != EVeinType.Oil)
            vein.amount = Mathf.RoundToInt((float) vein.amount);
          if (vein.amount < 1)
            vein.amount = 1;
          vein.productId = veinProducts[index7];
          vein.pos = normalized + vector3_5;
          vein.minerCount = 0;
          float num18 = data.QueryHeight(vein.pos);
          data.EraseVegetableAtPoint(vein.pos);
          vein.pos = vein.pos.normalized * num18;
          if (this.planet.waterItemId == 0 || (double) num18 >= (double) this.planet.radius)
          {
            this.planet.veinAmounts[(int) eveinType] += (long) vein.amount;
            ++this.planet.veinGroups[index6].count;
            this.planet.veinGroups[index6].amount += (long) vein.amount;
            data.AddVeinData(vein);
          }
        }
      }
      vector2List.Clear();
    }
    
    public virtual void GenerateVeins(StarData star, GalaxyData galaxy)
    {
      ThemeProto themeProto = LDB.themes.Select(this.planet.theme);
      if (themeProto == null)
        return;
      URandom1 urandom1_1 = new URandom1(this.planet.seed);
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      urandom1_1.Next();
      VeinProto[] veinProtos = PlanetModelingManager.veinProtos;
      int[] numArray1 = new int[veinProtos.Length];
      if (themeProto.VeinSpot != null)
        Array.Copy((Array) themeProto.VeinSpot, 0, (Array) numArray1, 1, Math.Min(themeProto.VeinSpot.Length, numArray1.Length - 1));
      float p = 1f;
      ESpectrType spectr = star.spectr;
      switch (star.type)
      {
        case EStarType.MainSeqStar:
          switch (spectr)
          {
            case ESpectrType.M:
              p = 2.5f;
              break;
            case ESpectrType.K:
              p = 1f;
              break;
            case ESpectrType.G:
              p = 0.7f;
              break;
            case ESpectrType.F:
              p = 0.6f;
              break;
            case ESpectrType.A:
              p = 1f;
              break;
            case ESpectrType.B:
              p = 0.4f;
              break;
            case ESpectrType.O:
              p = 1.6f;
              break;
          }
          break;
        case EStarType.GiantStar:
          p = 2.5f;
          break;
        case EStarType.WhiteDwarf:
          p = 3.5f;
          ++numArray1[9];
          ++numArray1[9];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.449999988079071; ++index)
            ++numArray1[9];
          ++numArray1[10];
          ++numArray1[10];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.449999988079071; ++index)
            ++numArray1[10];
          ++numArray1[12];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.5; ++index)
            ++numArray1[12];
          break;
        case EStarType.NeutronStar:
          p = 4.5f;
          ++numArray1[14];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.649999976158142; ++index)
            ++numArray1[14];
          break;
        case EStarType.BlackHole:
          p = 5f;
          ++numArray1[14];
          for (int index = 1; index < 12 && urandom1_1.NextDouble() < 0.649999976158142; ++index)
            ++numArray1[14];
          break;
      }
      for (int index1 = 0; index1 < themeProto.RareVeins.Length; ++index1)
      {
        int rareVein = themeProto.RareVeins[index1];
        float num2 = star.index != 0 ? themeProto.RareSettings[index1 * 4 + 1] : themeProto.RareSettings[index1 * 4];
        float rareSetting1 = themeProto.RareSettings[index1 * 4 + 2];
        float num4 = 1f - Mathf.Pow(1f - num2, p);
        if (urandom1_1.NextDouble() < (double) num4)
        {
          ++numArray1[rareVein];
          for (int index2 = 1; index2 < 12 && urandom1_1.NextDouble() < (double) rareSetting1; ++index2)
            ++numArray1[rareVein];
        }
      }
      this.planet.veinSpotsSketch = numArray1;
    }

  }
}
